/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.etrs.formathlon.persistance.formation;

import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import net.etrs.formathlon.entity.formation.Inscription;
import net.etrs.formathlon.entity.formation.Session;
import net.etrs.formathlon.entity.utilisateur.Personnel;
import net.etrs.formathlon.entity.utilisateur.Utilisateur;
import net.etrs.formathlon.metier.exception.MetierException;
import net.etrs.formathlon.metier.service.EntiteManager;
import net.etrs.formathlon.metier.service.EntiteManager.NiveauHierarchique;
import net.etrs.formathlon.metier.utils.constantes.RoleSpring;
import net.etrs.formathlon.metier.utils.email.MailManager;
import net.etrs.formathlon.persistance.utilisateur.PersonnelFacade;
import net.etrs.formathlon.persistance.utils.AbstractFacade;
import net.etrs.formathlon.persistance.utils.JpaRequestNames;
import org.apache.commons.mail.EmailException;

/**
 * Facade pour la gestion de l'entité Inscription.
 * @author OPIF
 */
@Stateless
public class InscriptionFacade extends AbstractFacade<Inscription> {

    @EJB
    private PersonnelFacade personnelFacade;
    @EJB
    private SessionFacade sessionFacade;

    /**
     * Liste des inscriptions à valider pour une personne.
     * Cette méthode retournera, selon le rôle de l'utilisateur passé en paramètre,
     * la liste des inscriptions restant à valider.
     * @param user La personne pouvant valider les demandes.
     * @return La liste des demandes à valider le concernant.
     * @throws MetierException L'utilisateur possède un rôle incompatible avec son entité.
     */
    public List<Inscription> getListInscriptionAValider(Utilisateur user) throws MetierException {
        Inscription.Etat etat = null;
        NiveauHierarchique niveau = NiveauHierarchique.COURS;


        //Si l'utilisateur est chef de division
        if (user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_DIV)) {
            etat = Inscription.Etat.VALIDEE_COURS;
            niveau = NiveauHierarchique.DIVISION;
        }
        //Si l'utilisateur est chef de cours
        if (user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_COURS)) {
            etat = Inscription.Etat.DEMANDEE;
            niveau = NiveauHierarchique.COURS;
        }
        //Sinon l'utilisateur n'a pas le droit de lister de demandes.
        if (!user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_DIV)
                && !user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_COURS)) {
            throw new MetierException(MetierException.Type.CANT_LIST_INSCRIPTIONS);
        }

        //Récupération de l'entité correspondant au niveau de la personne
        String entite = EntiteManager.getEntite(user.getEntite(), niveau);

        return getEm().createNamedQuery(JpaRequestNames.LISTE_INSCRIPTIONS_A_VALIDER).setParameter("entite", entite + "%").setParameter("etat", etat).getResultList();
    }

    /**
     * Autoriser une demande d'inscription à une séance.
     * @param user L'utilisateur faisant la demande.
     * @param inscription L'inscription à autoriser.
     */
    public void autoriser(Utilisateur user, Inscription inscription) throws MetierException {
        //Si l'utilisateur est chef de division.
        if (user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_DIV)) {
            inscription.setEtat(Inscription.Etat.VALIDEE_DIVISION);
        }
        //Si l'utilisateur est chef de cours.
        if (user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_COURS)) {
            inscription.setEtat(Inscription.Etat.VALIDEE_COURS);
        }
        //Sinon l'utilisateur n'a pas le droit d'accepter la demande.
        if (!user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_DIV)
                && !user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_COURS)) {
            throw new MetierException(MetierException.Type.CANT_ACCEPT_INSCRIPTION);
        }
        update(inscription);
    }

    /**
     * Refuser une demande d'inscription à une séance.
     * @param user L'utilisateur faisant la demande.
     * @param inscription L'inscription à refuser.
     */
    public void refuser(Utilisateur user, Inscription inscription) throws MetierException {
        if (user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_DIV)
                || user.getListRoleSpring().contains(RoleSpring.ROLE_CHEF_COURS)) {
            inscription.setEtat(Inscription.Etat.REFUSEE);
            update(inscription);
            try {
                MailManager.envoiRefusInscription(inscription);
            } catch (EmailException ex) {
                throw new MetierException(MetierException.Type.MAIL_ERREUR_TECHNIQUE, ex);
            }
        } else {
            throw new MetierException(MetierException.Type.CANT_REFUSE_INSCRIPTION);
        }
    }

    /**
     * Inscription d'un personnel a une session sur une formation.
     * @param perso
     * @param session 
     */
    public void inscrire(Personnel perso, Session session, boolean chefDeCours) throws MetierException {

        Inscription inscription;
        try {
            inscription = (Inscription) getEm().createNamedQuery(JpaRequestNames.INSCRIPTION_DEJA_FAITE).setParameter("session", session).setParameter("personnel", perso).getSingleResult();
        } catch (NoResultException ex) {
            inscription = null;
        } catch (NonUniqueResultException ex) {
            inscription = null;
        }

        if (inscription == null) {
            inscription = newInstance();
            if (chefDeCours) {
                inscription.setEtat(Inscription.Etat.VALIDEE_COURS);
            } else {
                inscription.setEtat(Inscription.Etat.DEMANDEE);
            }
            inscription.setPersonnel(perso);
            inscription.setSession(session);
            create(inscription);
            session.getListInscription().add(inscription);
            sessionFacade.update(session);
            perso.getListInscription().add(inscription);
            personnelFacade.update(perso);
        } else {
            throw new MetierException(MetierException.Type.INSCRIPTION_YET_IN_BASE);
        }
    }

    /**
     * Renvoie toutes les sessions à l'exception des sessions supprimées.
     * @param personnel
     * @return 
     */
    public List<Inscription> getListInscriptionPourUnFormateur(Personnel personnel) {
        return getEm().createNamedQuery(JpaRequestNames.LISTE_INSCRIPTION_DU_FORMATEUR).setParameter("personnel", personnel).setParameter("etat", Inscription.Etat.SUPPRIMEE).getResultList();
    }

    /**
     * Archivage d'une inscription.
     * @param inscription 
     */
    public void supprimer(Inscription inscription) throws MetierException {
        if (inscription.isSupprimable()) {
            inscription.setEtat(Inscription.Etat.SUPPRIMEE);
            inscription.setArchive(true);
            update(inscription);
        } else {
            throw new MetierException(MetierException.Type.INSCRIPTION_ETAT_NON_VALIDE);
        }
    }

    /**
     * Annulation d'une inscription.
     * @param inscription 
     */
    public void annuler(Inscription inscription) throws MetierException {
        if (inscription.isAnnulable()) {
            inscription.setEtat(Inscription.Etat.ANNULEE);
            update(inscription);
        } else {
            throw new MetierException(MetierException.Type.INSCRIPTION_ETAT_NON_VALIDE);
        }
    }

    /**
     * Annulation d'une inscription de la part d'un personnel.
     * @param inscription 
     */
    public void desister(Inscription inscription, String motif) throws MetierException {
        if (inscription.isDesistable()) {
            inscription.setMotifDesist(motif);
            inscription.setEtat(Inscription.Etat.ANNULEE);
            update(inscription);
        } else {
            throw new MetierException(MetierException.Type.INSCRIPTION_ETAT_NON_VALIDE);
        }
    }

    /**
     * Renvoie le nombre d'inscriptions validée.
     * @param session La session comportant les inscriptions.
     * @return Le nombre d'inscriptions validée.
     */
    public int getNbInscrit(Session session) {
        return getListInscriptionValidees(session).size();
    }

    /**
     * Renvoie les inscriptions validées.
     * @param session La session comportant les inscriptions.
     * @return Les inscriptions validées.
     */
    public List<Inscription> getListInscriptionValidees(Session session) {
        return getEm().createNamedQuery(JpaRequestNames.LISTE_INSCRIPTION_VALIDEES).setParameter("session", session).setParameter("etatValideeDiv", Inscription.Etat.VALIDEE_DIVISION).setParameter("etatVerrouillee", Inscription.Etat.VERROUILLEE).getResultList();
    }

    /**
     * Renvoie les inscriptions non validées.
     * @param session La session comportant les inscriptions.
     * @return Les inscriptions non validées.
     */
    public List<Inscription> getListInscriptionNonValidees(Session session) {
        return getEm().createNamedQuery(JpaRequestNames.LISTE_INSCRIPTION_NON_VALIDEES).setParameter("session", session).setParameter("etatValideeDiv", Inscription.Etat.VALIDEE_DIVISION).setParameter("etatVerrouillee", Inscription.Etat.VERROUILLEE).getResultList();
    }

    /**
     * Renvoie la liste des inscription des subordonees d'un utilisateur (chef de cours)
     * afin d'annuler ou de désister son personnel.
     */
    public List<Inscription> getInscriptionSub(Utilisateur chefCours) throws MetierException {
        List<Inscription> retour = new ArrayList<Inscription>();
        List<Personnel> listSubordonnes = personnelFacade.getSubordonnes(chefCours);
        for (Personnel personnel : listSubordonnes) {
            if (!personnel.equals(chefCours.getPersonnel())) {
                for (Inscription inscripSub : personnel.getListInscription()) {
                    if (inscripSub.isDesistable() || inscripSub.isAnnulable()) {
                        retour.add(inscripSub);
                    }
                }
            }
        }
        return retour;
    }
}
